package peerToPeerFacebook.proj;


/**
 * Parser for input command
 *
 */
public class CommandParser
{
	public static final String CreateFileCommandName = "create";
	public static final String GetFileCommandName = "get";
	public static final String PutFileCommandName = "put";
	public static final String AppendFileCommandName = "append";
	public static final String DeleteFileCommandName = "delete";	

	public static final String CreateUserCommandName = "createUser";
	public static final String LoginCommandName = "login";
	public static final String LogoutCommandName = "logout";
	public static final String AcceptFriendRequestCommandName = "acceptFriendRequest";
	public static final String SendFriendRequestCommandName = "sendFriendRequest";
	public static final String PostMessageToAllCommandName = "postMessageToAll";
	public static final String ReadAllMessagesCommandName = "readAllMessages";

	private String commandString;
	
	/**
   * This method is used in PostMessageToAll, since the message can have
   * spaces, this method extracts the message from the user command seperated
   * by spaces.
   * @param tokens: The input user command
   * @return: The String message
   */
  public static String trimFirstArgument(String[] tokens)
  {
    String temp = "";
    for(int i = 1 ; i < tokens.length ; i++)
    {
       temp += " " + tokens[i];
    }
    
    // Trim first space
    return temp.substring(1);
    
  }
  
	/**
   * This method is used in Put parse method, since the contents can have
   * spaces, this method extracts the contents string from the user command seperated
   * by spaces.
   * @param tokens: The input user command
   * @return: The String contents
   */
  public static String trimThreeArguments(String[] tokens)
  {
    String temp = "";
    for(int i = 0 ; i < tokens.length ; i++)
     {
       temp += " " + tokens[i];
     }
    
    String temp1 = temp.replace(tokens[0] + " ","");
    String temp2 = temp1.replace(tokens[1]+" ","");
    return temp2.replace(tokens[2]+" ","");
    
  }
	
	public CommandParser(String command)
	{
		ArgumentValidator.IsNotNullOrEmpty("command", command);
		this.commandString = command;
	}
	
	IFileServerCommand parseCreateRequest(String[] tokens)
	{
		if (tokens.length != 3)
		{			
			System.out.println("Invalid create command: expected 3 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
			return null;
		}
		
		int serverID = Integer.parseInt(tokens[1]);
		String fileName = tokens[2];		
		
		return new FileServerCommand(CreateFileCommandName, serverID, fileName);
	}
	
	IFileServerCommand parseGetRequest(String[] tokens)
	{
		if (tokens.length != 3)
		{			
		  System.out.println("Invalid get command: expected 3 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		int serverID = Integer.parseInt(tokens[1]);
		String fileName = tokens[2];
		
		return new FileServerCommand(GetFileCommandName, serverID, fileName);
	}
	
	IFileServerCommand parsePutRequest(String[] tokens)
	{
		if (tokens.length < 4)
		{			
		  System.out.println("Invalid put command: expected 4 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		int serverID = Integer.parseInt(tokens[1]);
		String fileName = tokens[2];
		String contents = trimThreeArguments(tokens);
		
		return new FileServerCommand(PutFileCommandName, serverID, fileName, contents);
	}
	
	IFileServerCommand parseAppendRequest(String[] tokens)
	{
		if (tokens.length < 4)
		{			
		  System.out.println("Invalid append command: expected 4 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		int serverID = Integer.parseInt(tokens[1]);
		String fileName = tokens[2];
		String contents = trimThreeArguments(tokens);
		
		return new FileServerCommand(AppendFileCommandName, serverID, fileName, contents);
	}

	IFileServerCommand parseDeleteRequest(String[] tokens)
	{
		if (tokens.length != 3)
		{			
		  System.out.println("Invalid delete command: expected 3 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		int serverID = Integer.parseInt(tokens[1]);
		String fileName = tokens[2];		
		
		return new FileServerCommand(DeleteFileCommandName, serverID, fileName);
	}

	IFacebookCommand parseCreateUserRequest(String[] tokens)
	{
		if (tokens.length != 2)
		{
		  System.out.println("Invalid create user command: expected 2 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		String username = tokens[1];
		return new FacebookCommand(CreateUserCommandName, username);
	}

	IFacebookCommand parseLoginRequest(String[] tokens)
	{
		if (tokens.length != 2)
		{
		  System.out.println("Invalid login command: expected 2 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		String username = tokens[1];
		return new FacebookCommand(LoginCommandName, username);
	}

	IFacebookCommand parseLogoutRequest()
	{
		return new FacebookCommand(LogoutCommandName);
	}
	
	IFacebookCommand parseAcceptFriendRequest(String[] tokens)
	{
		if (tokens.length != 2)
		{
		  System.out.println("Invalid accept friend command: expected 2 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		String friendName = tokens[1];
		return new FacebookCommand(AcceptFriendRequestCommandName, friendName);
	}

	IFacebookCommand parseSendFriendRequest(String[] tokens)
	{
		if (tokens.length != 2)
		{
		  System.out.println("Invalid send friend command: expected 2 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		String friendName = tokens[1];
		return new FacebookCommand(SendFriendRequestCommandName, friendName);
	}
	
	IFacebookCommand parsePostMessageRequest(String[] tokens)
	{
		if (tokens.length < 2)
		{
		  System.out.println("Invalid post message command: expected 2 arguments but " + tokens.length + " were supplied. Input command: '" + this.commandString + "'");
		  return null;
		}
		
		 String message = trimFirstArgument(tokens);
	  
		return new FacebookCommand("postMessageToAll", "all", message);
	}

	IFacebookCommand parseReadMsgRequest()
	{
		return new FacebookCommand("readAllMessages");
	}
	
	private static String[] splitCommandIntoTokens(String command)
	{
		String delimiterIgnoringMultipleSpaces = "[ ]+";
		return command.split(delimiterIgnoringMultipleSpaces);
	}	

	public ICommand parseCommand()
	{	
		String tokens[] = splitCommandIntoTokens(commandString);
		
		String commandName = tokens[0];
	
		if (commandName.equalsIgnoreCase(CreateFileCommandName)) 
		{
			return parseCreateRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(GetFileCommandName))
		{
			return parseGetRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(PutFileCommandName))
		{
			return parsePutRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(AppendFileCommandName))
		{
			return parseAppendRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(DeleteFileCommandName))
		{
			return parseDeleteRequest(tokens);
		}	
		else if (commandName.equalsIgnoreCase(LoginCommandName))
		{
			return parseLoginRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(LogoutCommandName))
		{
			return parseLogoutRequest();
		}
		else if (commandName.equalsIgnoreCase(CreateUserCommandName))
		{
			return parseCreateUserRequest(tokens);
		}		
		else if (commandName.equalsIgnoreCase(PostMessageToAllCommandName))
		{
			return parsePostMessageRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(SendFriendRequestCommandName))
		{
			return parseSendFriendRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(AcceptFriendRequestCommandName))
		{
			return parseAcceptFriendRequest(tokens);
		}
		else if (commandName.equalsIgnoreCase(ReadAllMessagesCommandName))
		{
			return parseReadMsgRequest();
		}
		else
		{
			throw new IllegalArgumentException("Command parser: Unsupported command '" + this.commandString + "'");
		}
	}
}
